﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Media.Capture;
using Windows.Media.Devices;
using Windows.Storage;
using Windows.UI.Core;

namespace Padsurface.App.ViewModels
{
    public partial class PadViewModel
    {
		private const string TemporarySampleFileName = "temp-padsurface-sample.wav";
        private const string SuggestedSampleFileName = "padsurace-sample.wav";
        private CancellationTokenSource _updateSamplingTimeCancellation;

        private bool _isSamplingToggled;
        public bool IsSamplingToggled
        {
            get { return _isSamplingToggled; }
            set
            {
                SetProperty(ref _isSamplingToggled, value);
                OnSamplingToggled();
            }
        }

        private bool _isSampling;
        public bool IsSampling
        {
            get { return _isSampling; }
            set { SetProperty(ref _isSampling, value); }
        }

        private string _samplingTime;
        public string SamplingTime
        {
            get { return _samplingTime; }
            set { SetProperty(ref _samplingTime, value); }
        }

        private bool _isMicrophoneDisabled;
        public bool IsMicrophoneDisabled
        {
            get { return _isMicrophoneDisabled; }
            set { SetProperty(ref _isMicrophoneDisabled, value); }
        }

        private void OnSamplingToggled()
        {
            lock (_lock)
            {
                if (IsMicrophoneDisabled)
                    IsMicrophoneDisabled = false;

                if (!IsSampling)
                    StartSampling();
                else
                    StopSampling();
            }
        }

        private async void StartSampling()
        {
            IsSampling = true;
            
            var temporaryFolder = ApplicationData.Current.TemporaryFolder;
            var temporaryFile = await temporaryFolder.CreateFileAsync(TemporarySampleFileName, CreationCollisionOption.ReplaceExisting);

            try
            {
                await RequestMicrophoneAccess();

                await _waveFileInput.StartRecording(temporaryFile);

                _updateSamplingTimeCancellation = new CancellationTokenSource();
                UpdateTimer(() => SamplingTime = _waveFileInput.Length.ToString(@"mm\:ss\.fff"), _updateSamplingTimeCancellation.Token);
            }
            catch (UnauthorizedAccessException)
            {
                IsMicrophoneDisabled = true;

                TryCleanupTemporarySampleFile();
            }
        }

        /// <summary>
        /// Only launches consent prompt on first use; always throws UnauthorizedAccessException when permission denied
        /// </summary>
        private async Task RequestMicrophoneAccess()
        {
            var settings = new MediaCaptureInitializationSettings
            {
                AudioDeviceId = MediaDevice.GetDefaultAudioCaptureId(AudioDeviceRole.Default),
                StreamingCaptureMode = StreamingCaptureMode.Audio
            };

            await new MediaCapture().InitializeAsync(settings);
        }

        private async void StopSampling()
        {
            IsSampling = false;
            _updateSamplingTimeCancellation.Cancel();

            await _waveFileInput.StopRecording();

            try
            {
                var samplingDestination = await _filePicker.SaveWaveFileAsync(SuggestedSampleFileName);
                var isCancelled = (samplingDestination == null);
                if (isCancelled)
                    return;

                await _waveFileInput.StorageFile.CopyAndReplaceAsync(samplingDestination);

                AddSound(samplingDestination);
            }
            finally
            {
                TryCleanupTemporarySampleFile();
            }
        }

        private async void TryCleanupTemporarySampleFile()
        {
            try
            {
                var temporaryFolder = ApplicationData.Current.TemporaryFolder;
                var temporaryFile = await temporaryFolder.GetFileAsync(TemporarySampleFileName);

                if (temporaryFile != null)
                    await temporaryFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
            }
            catch (Exception ex)
            {
                Debug.WriteLine("TryCleanupTemporarySampleFile failed:");
                Debug.WriteLine(ex);
            }
        }
    }
}